package com.alex.wechat.app.gateway;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alex.wechat.app.config.WxAppContext;
import com.alex.wechat.mp.config.WxConsts;
import com.alex.wechat.mp.util.WxCryptUtilEx;

import cn.binarywang.wx.miniapp.api.WxMaConfigEx;
import me.chanjar.weixin.message.bean.WxXmlMessage;
import me.chanjar.weixin.message.rule.WxMessageRouter;

/**
 * 负责与微信服务器通信。
 * 
 * @author Debenson
 * @since 0.1
 */
@Controller
@RequestMapping("/wxAppCoreController")
public class WxAppCoreController {
  private static final Logger logger = LoggerFactory.getLogger(WxAppCoreController.class);

  @Autowired
  private WxMaConfigEx appConfigStorage;
  @Autowired
  private WxMessageRouter wxRouter;

  /**
   * 微信小程序webservice主服务接口，提供与微信服务器的信息交互
   *
   * @param request
   * @param response
   * @throws Exception
   */
  @RequestMapping(params = "wechat")
  public void wechat(HttpServletRequest request, HttpServletResponse response) throws Exception {
    response.setContentType("text/html;charset=utf-8");
    response.setStatus(HttpServletResponse.SC_OK);

    if (!WxCryptUtilEx.checkSignature(appConfigStorage.getToken(), request)) {
      // 消息签名不正确，说明不是公众平台发过来的消息
      response.getWriter().println("非法请求");
      return;
    }

    final String echoStr = request.getParameter(WxConsts.PARAM_ECHO_STR);
    if (StringUtils.isNotBlank(echoStr)) {
      // 说明是一个仅仅用来验证的请求，回显echostr
      String echoStrOut = String.copyValueOf(echoStr.toCharArray());
      response.getWriter().println(echoStrOut);
      return;
    }

    String encryptType = request.getParameter(WxConsts.PARAM_ENCRYPT_TYPE);
    if (StringUtils.isBlank(encryptType)) {
      encryptType = WxConsts.ENCRYPT_TYPE_RAW;
    }
    if (WxConsts.ENCRYPT_TYPE_RAW.equalsIgnoreCase(encryptType)) {
      // 使用明码传输
      processRawEncrypt(request, response);

    } else if (WxConsts.ENCRYPT_TYPE_AES.equalsIgnoreCase(encryptType)) {
      // 是aes加密的消息
      processAesEncrypt(request, response);

    } else {
      response.getWriter().println("不可识别的加密类型");
    }
  }

  /**
   * @param request
   * @param response
   * @throws Exception
   */
  private void processRawEncrypt(HttpServletRequest request, HttpServletResponse response)
      throws Exception {
    // 明文传输的消息
    response.setContentType("application/xml; charset=UTF-8");
    WxXmlMessage inMessage = WxXmlMessage.fromXml(request.getInputStream());

    initWxContext(inMessage);
    final String outMessage = this.wxRouter.routeApp(inMessage);
    if (outMessage != null) {
      if (logger.isInfoEnabled()) {
        logger.info("小程序回复内容为: {}", outMessage);
      }
      response.getWriter().write(outMessage);
    }
  }

  /**
   * @param request
   * @param response
   * @throws Exception
   */
  private void processAesEncrypt(HttpServletRequest request, HttpServletResponse response)
      throws Exception {
    String msgSignature = request.getParameter(WxConsts.PARAM_MSG_SIGNATURE);
    String nonce = request.getParameter(WxConsts.PARAM_NONCE);
    String timestamp = request.getParameter(WxConsts.PARAM_TIMESTAMP);
    response.setContentType("application/xml; charset=UTF-8");

    WxXmlMessage inMessage = WxCryptUtilEx.fromEncryptedXml(request.getInputStream(),
        appConfigStorage, timestamp, nonce, msgSignature);
    if (logger.isInfoEnabled()) {
      logger.info("小程序消息解密后内容为：\n{} ", inMessage.toString());
    }

    initWxContext(inMessage);
    final String outMessage = this.wxRouter.routeApp(inMessage);
    if (outMessage != null) {
      if (logger.isInfoEnabled()) {
        logger.info("回复小程序内容为(加密前): {}", outMessage);
      }
      response.getWriter().write(WxCryptUtilEx.toEncryptedXml(outMessage, appConfigStorage));
    } else {
      if (logger.isInfoEnabled()) {
        logger.info("没有回复内容");
      }
    }
  }

  /**
   * 初始化微信上下文环境。
   * 
   * @param inMessage
   */
  private void initWxContext(WxXmlMessage inMessage) {
    // 设置当前公众号
    WxAppContext.setOriginalId(inMessage.getToUser());
  }

}
